package org.linkality.r_osgi.service.discovery.mdns;

import java.io.IOException;

import java.util.Dictionary;
import java.util.Hashtable;

import javax.jmdns.JmDNS;
import javax.jmdns.ServiceInfo;

import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.apache.log4j.Logger;
import ch.ethz.iks.r_osgi.URI;
import ch.ethz.iks.r_osgi.service_discovery.ServiceDiscoveryHandler;

/**
 * A service discovery handler that announces and discovers R-OSGi services via mDNS.
 * <p>
 * It relies on the JmDNS bundle.
 * 
 * @author Julian Schuette
 *
 */
public class MDNSServiceDiscoveryHandler implements ServiceDiscoveryHandler {
	private final static Logger logger = Logger.getLogger(MDNSServiceDiscoveryHandler.class);
	private static final String ROSGI_SERVICE_TYPE = "_rosgi._tcp.local.";
	private JmDNS jmdns;
	private Hashtable<ServiceReference, ServiceInfo> registrations = new Hashtable<ServiceReference, ServiceInfo>();


	public MDNSServiceDiscoveryHandler(final BundleContext context) {
		try {
			//Setting debug level for JmDNS
			System.setProperty("jmdns.debug", "2");
			jmdns = new JmDNS();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void shutdown() {
		jmdns.unregisterAllServices();
		registrations = new Hashtable<ServiceReference, ServiceInfo>();
	}

	/**
	 * This method is called by R-OSGi whenever a new R-OSGi service has been registered. It announces the service via mDNS.
	 */
	public void registerService(final ServiceReference ref,
			final Dictionary properties, final URI uri) {
		try {
			jmdns.registerServiceType(ROSGI_SERVICE_TYPE);
			final Hashtable prop = new Hashtable();
//			Enumeration keys = properties.keys();
//			while (keys.hasMoreElements()) {
//				String key = (String) keys.nextElement();
//				String value = (String) properties.get(key);
//				prop.put(key, value);
//			}
			
			//The R-OSGi URI is stored under the "uri" property
			prop.put("uri", uri.toString());
			
			PublishingThreadPool mtpe = new PublishingThreadPool();
	        mtpe.runTask(new Runnable() {
	            public void run() {
	            	try {
	        			logger.info("Registering via mDNS: " + uri + " " + ref.getBundle().getSymbolicName());
		    			ServiceInfo info = new ServiceInfo("_rosgi._tcp.local.", ref.getBundle().getSymbolicName().replace('.', '|'),
		    					1268, 0, 0, prop);
		    			jmdns.registerService(info);
		    			registrations.put(ref,info);
	            	} catch (IOException e) {
	            		logger.error(e.getMessage(),e);
	            	}
	            }
	        });
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	public void unregisterService(final ServiceReference ref) {
		assert ref!=null;
		
		logger.info("Unregistering at mDNS: " + ref.getBundle().getSymbolicName() + " [" + ref.getBundle().getBundleId() + "]");
		ServiceInfo info = registrations.get(ref);
		if (info != null) {
			jmdns.unregisterService(info);
			System.out.println("  Unregistered " + info.getName());
		} else {
			System.out.println("No service was registered");
		}
	}
}
